package com.supplychain.scm.core.common.advice;

import com.supplychain.scm.core.common.annotation.IgnoreResult;
import com.supplychain.scm.core.common.constant.RequestConstants;
import com.supplychain.scm.core.common.util.R;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.MDC;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.core.MethodParameter;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import java.lang.annotation.Annotation;

/**
 * @author liyang
 * @version 1.0.0
 * @ClassName ResponseAdvice
 * @Description 统一结果处理
 * @createTime 17:34:00 2023/05/20
 */
@RestControllerAdvice
@ConditionalOnProperty(prefix = "dby.response.advice", value = "enabled", havingValue = "true",matchIfMissing = true)
public class ResponseAdvice implements ResponseBodyAdvice<Object> {

    private static final Class<? extends Annotation> ANNOTATION_TYPE = RestController.class;
    private static final Class<? extends Annotation> RESPONSE_ANNOTATION_TYPE = com.supplychain.scm.core.common.annotation.ResponseAdvice.class;
    private static final Class<? extends Annotation> IGNORE_ANNOTATION_TYPE = IgnoreResult.class;

    @Override
    public boolean supports(MethodParameter returnType, Class converterType) {
        return !returnType.hasMethodAnnotation(IGNORE_ANNOTATION_TYPE) &&
                (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ANNOTATION_TYPE) ||
                AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), RESPONSE_ANNOTATION_TYPE) ||
                returnType.hasMethodAnnotation(RESPONSE_ANNOTATION_TYPE));
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        String requestId = MDC.get(RequestConstants.REQUEST_ID);
        if(body instanceof R) {
            if(StringUtils.isNotBlank(requestId)) {
                R<?> result = (R<?>) body;
                result.setRequestId(requestId);
            }
            return body;
        } else {
            R<Object> result = R.ok(body);
            result.setRequestId(requestId);
            return result;
        }
    }
}
